/*
 * Copyright (c) 2013 Mohammad Mehdi Saboorian
 *
 * This is part of moor, a wrapper for libarchive
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include "MemoryWriterCallback.h"

#include <archive.h>
#include <stdexcept>
#include <iterator>

struct write_memory_data
{
	std::list<unsigned char> * buff;
};

static int32_t memory_write_close(struct archive *, void *);
static int32_t memory_write_open(struct archive *, void *);
static ssize_t memory_write(struct archive *, void *, const void *buff, size_t);

int write_open_memory(struct archive *a, std::list<unsigned char> * buf)
{
	struct write_memory_data *mine = new write_memory_data;

	if (mine == NULL)
		throw std::runtime_error("no memory");

	mine->buff = buf;
	return (archive_write_open(a, mine, memory_write_open, memory_write, memory_write_close));
}
int32_t memory_write_open(struct archive *a, void *clientData)
{
	(void)clientData; /* UNUSED */
	/* Disable padding if it hasn't been set explicitly. */
	if (-1 == archive_write_get_bytes_in_last_block(a))
		archive_write_set_bytes_in_last_block(a, 1);
	return (ARCHIVE_OK);
}
ssize_t memory_write(struct archive *a, void *clientData, const void *buff, size_t length)
{
	(void)a; /* UNUSED */
	struct write_memory_data *mine;
	mine = (write_memory_data*)clientData;

	std::copy((unsigned char*)buff, (unsigned char*)buff + length, std::back_inserter(*(mine->buff)));
	return (length);
}

int32_t memory_write_close(struct archive *a, void *clientData)
{
	struct write_memory_data *mine;
	(void)a; /* UNUSED */
	mine = (write_memory_data*)clientData;
	delete mine;
	return (ARCHIVE_OK);
}
